package com.test.A39;

import java.util.Arrays;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.DefaultApplicationArguments;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.ClassPathResource;

public class A39_3 {
	
	    public static void main(String[] args) throws Exception {
	    	test2(args);
	    }
	 
	    
	     /****
	      * 读取配置类，xml或者包位置   实现run的方法
	      * @param args
	      * @throws Exception
	      */
		 @SuppressWarnings("all")
		 public static void test2(String[] args) throws Exception {
			 SpringApplication app = new SpringApplication();
		        
		        //初始化容器
		        app.addInitializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() {
		            @Override
		            public void initialize(ConfigurableApplicationContext applicationContext) {
		                System.out.println("执行初始化器增强...");
		            }
		        });

		        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 2. 封装启动 args");
		        DefaultApplicationArguments arguments = new DefaultApplicationArguments(args);
		        
		        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 8. 创建容器");
		        GenericApplicationContext context = createApplicationContext(WebApplicationType.SERVLET);

		        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 9. 初始化容器");
		        for (ApplicationContextInitializer initializer : app.getInitializers()) {
		            initializer.initialize(context);
		        }

		        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 10. 加载 bean 定义");
		        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
		        AnnotatedBeanDefinitionReader reader1 = new AnnotatedBeanDefinitionReader(beanFactory);//把bean定义加载到容器中
		        reader1.register(Config.class);//读取配置类 
		        XmlBeanDefinitionReader reader2 = new XmlBeanDefinitionReader(beanFactory);//读取xml配置文件
		        reader2.loadBeanDefinitions(new ClassPathResource("b03.xml"));
		        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanFactory);
		        //扫描包
		        scanner.scan("com.test.A39.sub");
		        
		        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 11. refresh 容器");
		        context.refresh();

		        for (String name : context.getBeanDefinitionNames()) {
		            System.out.println("name:" + name + " 来源：" + beanFactory.getBeanDefinition(name).getResourceDescription());
		        }

		        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 12. 执行 runner");
		        //两种实现CommandLineRunner和ApplicationRunner
		        for (CommandLineRunner runner : context.getBeansOfType(CommandLineRunner.class).values()) {
		            runner.run(args);
		        }

		        for (ApplicationRunner runner : context.getBeansOfType(ApplicationRunner.class).values()) {
		            runner.run(arguments); //arguments参数是2封装的参数
		        }
			
		}
		 
		 
	  /***
	   * 得到config的bean的来源
	   * @param args
	   * @throws Exception
	   */
	 @SuppressWarnings("all")
	 public static void test1(String[] args) throws Exception {
		 SpringApplication app = new SpringApplication();
	        
	        //初始化容器
	        app.addInitializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() {
	            @Override
	            public void initialize(ConfigurableApplicationContext applicationContext) {
	                System.out.println("执行初始化器增强...");
	            }
	        });

	        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 2. 封装启动 args");
	        
	        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 8. 创建容器");
	        GenericApplicationContext context = createApplicationContext(WebApplicationType.SERVLET);

	        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 9. 初始化容器");
	        for (ApplicationContextInitializer initializer : app.getInitializers()) {
	            initializer.initialize(context);
	        }

	        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 10. 加载 bean 定义");
	        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
	        AnnotatedBeanDefinitionReader reader1 = new AnnotatedBeanDefinitionReader(beanFactory);//把bean定义加载到容器中
	        reader1.register(Config.class);//读取配置类 
	        
	        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 11. refresh 容器");
	        context.refresh();

	        for (String name : context.getBeanDefinitionNames()) {
	            System.out.println("name:" + name + " 来源：" + beanFactory.getBeanDefinition(name).getResourceDescription());
	        }

	        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 12. 执行 runner");    
	       
		
	}


	 /** 
	  * 判断容器是哪一种类型  
	  * @param type
	  * @return
	  */
	    private static GenericApplicationContext createApplicationContext(WebApplicationType type) {
	        GenericApplicationContext context = null;
	        /****  ->语法在jdk12使用
	        switch (type) {
	            case SERVLET -> context = new AnnotationConfigServletWebServerApplicationContext();
	            case REACTIVE -> context = new AnnotationConfigReactiveWebServerApplicationContext();
	            case NONE -> context = new AnnotationConfigApplicationContext();
	        }
	        
	        **/
	        switch (type) {
            case SERVLET  : 
            	context = new AnnotationConfigServletWebServerApplicationContext();
            	break;
            case REACTIVE : 
            	   context = new AnnotationConfigReactiveWebServerApplicationContext();
            	   break;
            case NONE : 
            	 context = new AnnotationConfigApplicationContext();
            	 break;
        }
	        
	        return context;
	    }

	    static class Bean4 {

	    }

	    static class Bean5 {

	    }

	    static class Bean6 {

	    }

	    @Configuration
	    static class Config {
	        @Bean
	        public Bean5 bean5() {
	            return new Bean5();
	        }

	        @Bean
	        public ServletWebServerFactory servletWebServerFactory() {
	            return new TomcatServletWebServerFactory();
	        }

	        @Bean
	        public CommandLineRunner commandLineRunner() {
	            return new CommandLineRunner() {
	                @Override
	                public void run(String... args) throws Exception {
	                    System.out.println("commandLineRunner()..." + Arrays.toString(args));
	                }
	            };
	        }

	        /****
	         *  
	         * @return
	         */
	        @Bean
	        public ApplicationRunner applicationRunner() {
	            return new ApplicationRunner() {
	                @Override
	                public void run(ApplicationArguments args) throws Exception {
	                    System.out.println("applicationRunner()..." + Arrays.toString(args.getSourceArgs()));//得到所有的参数
	                    System.out.println(args.getOptionNames()); //得到有选项的值
	                    System.out.println(args.getOptionValues("server.port"));
	                    System.out.println(args.getNonOptionArgs());
	                    
	                }
	            };
	        }
	    }
}
